﻿/*
 
Celerity: Sensory Overload
Copright 2012 by Adam Hill, David Gannon, Thomas Tamblyn & Patrick Ytting
Contact: adam.hill@outlook.com
Website: adamhill.org
Licence: MS-Pl Licence
  
 */

namespace Celerity.Audio
{
    using Celerity.Content;
    using Celerity.Data;
    using Microsoft.Xna.Framework.Audio;
    using System;

    public sealed class AudioModule : IDisposable
    {
        // Startup logic
        bool hasMusicStarted = false;

        #region Audio
        // XACT objects
        AudioEngine engine;
        WaveBank waveBank;
        SoundBank soundBank;

        // Channels
        AudioCategory musicChannel1;
        AudioCategory musicChannel2;
        AudioCategory musicChannel3;
        AudioCategory musicChannel4;
        AudioCategory ambienceChannel;
        AudioCategory sfxChannel;
        #endregion /Audio

        public void Initialize()
        {
            // Init XACT objects
            engine = new AudioEngine(AudioLibrary.PathEngine);
            waveBank = new WaveBank(engine, AudioLibrary.PathWaveBank);
            soundBank = new SoundBank(engine, AudioLibrary.PathSoundBank);

            // Init channels
            musicChannel1 = engine.GetCategory(AudioLibrary.ChannelMusic1);
            musicChannel2 = engine.GetCategory(AudioLibrary.ChannelMusic2);
            musicChannel3 = engine.GetCategory(AudioLibrary.ChannelMusic3);
            musicChannel4 = engine.GetCategory(AudioLibrary.ChannelMusic4);
            ambienceChannel = engine.GetCategory(AudioLibrary.ChannelAmbience);
            sfxChannel = engine.GetCategory(AudioLibrary.ChannelSFX);
        }

        public void Update(float chaosFactor)
        {
            // All sounds will be multiplied by this allowing a global mute function
            float muteMultiplier = GlobalGameStates.MuteState == MuteState.Muted ? 0f : 1f;

            // Set looping music playing first time only
            if (!hasMusicStarted)
            {
                hasMusicStarted = true;
                if (CeleritySettings.PlayMusic)
                {
                    soundBank.PlayCue(AudioLibrary.Music_Layer1);
                    soundBank.PlayCue(AudioLibrary.Music_Layer2);
                    soundBank.PlayCue(AudioLibrary.Music_Layer3);
                    soundBank.PlayCue(AudioLibrary.Music_ShortIntro);
                    soundBank.PlayCue(AudioLibrary.Ambience);
                }
            }

            // Set the volumes
            float normalVolume = 1f * muteMultiplier;
            ambienceChannel.SetVolume(normalVolume);
            musicChannel1.SetVolume(normalVolume);
            musicChannel2.SetVolume(DynamicVolume(chaosFactor, 0.3f) * muteMultiplier);
            musicChannel3.SetVolume(DynamicVolume(chaosFactor, 0.7f) * muteMultiplier);
            musicChannel4.SetVolume(normalVolume);
            sfxChannel.SetVolume(normalVolume);

            // Update the engine
            engine.Update();
        }

        #region Helper Method
        float DynamicVolume(float chaosFactor, float threshold)
        {
            if (threshold >= 1f)
            {
                throw new ArgumentException("Audio Module - Dynamic Volume: Threshold must be less than 1.");
            }

            float off = 0f;
            return chaosFactor > threshold ? (chaosFactor - threshold) / (1f - threshold) : off;
        }
        #endregion /Helper Method

        #region Play Methods
        public void PlayClick()
        {
            soundBank.PlayCue(AudioLibrary.Blip);
        }

        public void PlayCrash()
        {
            soundBank.PlayCue(AudioLibrary.Ship_HitsBlock);
        }

        public void PlayDie()
        {
            soundBank.PlayCue(AudioLibrary.Ship_HitsAndDies);
        }

        public void PlaySmartBomb()
        {
            soundBank.PlayCue(AudioLibrary.SmartBomb);
            soundBank.PlayCue(AudioLibrary.Ship_HitsAndDies);
        }
        #endregion /Play Methods

        public void Dispose()
        {
            engine.Dispose();
            waveBank.Dispose();
            soundBank.Dispose();
            this.Dispose();
            GC.SuppressFinalize(this);
        }
    }
}
